// Aloudin (Albert) Akhriev, 1998-2001.

#ifndef  ALIB_A_FILTER_H
#define  ALIB_A_FILTER_H

#include <limits>
#include <cassert>

//==========================================================================
// Class generates and keeps odd number of filters with slightly smoothing
// parameters. Class contains both smoothing and differentiating filters.
// AFilter should be used ONLY as a base class for any actual one.
//==========================================================================
class AFilter
{
 public:
  enum FilterType
  {
    GAUSS = 1,
    EXP_X = 2
  };

 protected:
  float ** m_smooth;    // smoothing filters with different variances
  float ** m_differ;    // differentiating filters with different variances
  float ** m_double;    // double differentiating filters with different variances
  double   m_param;     // smoothing parameter of central filter
  double   m_dParam;    // increment of smoothing parameter
  int      m_nFilter;   // number of filters of both kind (always odd!)
  int      m_size;      // length of a filter (the same for all filters)

  virtual void   ComputeFilter(float * sf, float * df, float * ddf, double param) =0;
  virtual int    GetFilterLength(int nFilter, double param, double dParam) =0;
  virtual double ValidateParameter(double param) =0;

 public:
  AFilter();
  virtual ~AFilter();

  void Clear();
  void Create(int nFilter, double param, double fraction = 0.01);

  double Param()   const { return m_param;   }
  double Delta()   const { return m_dParam;  }
  int    Size()    const { return m_size;    }
  int    NFilter() const { return m_nFilter; }

  virtual int Type() const =0;
 
  double Ratio() const
  {
	  return (m_dParam > std::numeric_limits<float>::epsilon()) ? (m_param/m_dParam) : 0.0;
  }

  const float * SF(int filterNo) const
  { 
    assert( filterNo>=0 && filterNo<m_nFilter );
    return m_smooth[filterNo];
  }

  const float * DF(int filterNo) const
  { 
    assert( filterNo>=0 && filterNo<m_nFilter );
    return m_differ[filterNo];
  }

  const float * DDF(int filterNo) const
  { 
    assert( filterNo>=0 && filterNo<m_nFilter );
    return m_double[filterNo];
  }
};

#endif   // ALIB_A_FILTER_H
